﻿namespace BadHabit.WPFTools
{
    using System;
    using System.Windows;
    using System.Windows.Controls;

    /// <summary>
    /// Provides a easy way to hide UI Elements based on the current thread IsInRole method.
    /// </summary>
    public class RoleChecker
    {
        public static readonly DependencyProperty RequiredVisibleRoleProperty = DependencyProperty.RegisterAttached("RequiredVisibleRole", typeof(string), typeof(RoleChecker), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnRequiredRoleChanged)));

        public static readonly DependencyProperty RequiredEnableRoleProperty = DependencyProperty.RegisterAttached("RequiredEnableRole", typeof(string), typeof(RoleChecker), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnRequiredRoleChanged)));

        public static readonly DependencyProperty RequiredEditRoleProperty = DependencyProperty.RegisterAttached("RequiredEditRole", typeof(string), typeof(RoleChecker), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnRequiredRoleChanged)));

        public static void SetRequiredVisibleRole(Control control, string value)
        {
            control.SetValue(RequiredVisibleRoleProperty, value);
            SetVisibility(control);
        }

        public static string GetRequiredVisibleRole(Control control)
        {
            return (string)control.GetValue(RequiredVisibleRoleProperty);
        }

        public static void SetRequiredEnableRole(Control control, string value)
        {
            control.SetValue(RequiredEnableRoleProperty, value);
            SetEnableality(control);
        }

        public static string GetRequiredEnableRole(Control control)
        {
            return (string)control.GetValue(RequiredEnableRoleProperty);
        }

        public static void SetRequiredEditRole(Control control, string value)
        {
            control.SetValue(RequiredEditRoleProperty, value);
            SetEnableality(control);
        }

        public static string GetRequiredEditRole(Control control)
        {
            return (string)control.GetValue(RequiredEditRoleProperty);
        }

        public static System.Security.Principal.GenericPrincipal ThreadPrincipal { get; set; }

        private static void OnRequiredRoleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is FrameworkElement))
            {
                throw new Exception("RequiredVisibleRole/RequiredEnableRole Property should be attached to a FrameworkElement only.");
            }

            FrameworkElement control = d as FrameworkElement;
            control.Loaded += new RoutedEventHandler(ControlLoaded);
        }

        private static void ControlLoaded(object sender, RoutedEventArgs e)
        {
            SetVisibility((FrameworkElement)sender);
            SetEnableality((FrameworkElement)sender);
            SetReadOnly((FrameworkElement)sender);
        }

        private static void SetVisibility(FrameworkElement control)
        {
            object o = control.GetValue(RequiredVisibleRoleProperty);

            if (o == null)
            {
                return;
            }

            if (ThreadPrincipal == null)
            {
                control.Visibility = Visibility.Collapsed;
                return;
            }

            if (!ThreadPrincipal.IsInRole(o.ToString()))
            {
                control.Visibility = Visibility.Collapsed;
            }
        }

        private static void SetEnableality(FrameworkElement control)
        {
            object o = control.GetValue(RequiredEnableRoleProperty);

            if (o == null)
            {
                return;
            }

            if (ThreadPrincipal == null)
            {
                return;
            }

            if (!ThreadPrincipal.IsInRole(o.ToString()))
            {
                control.IsEnabled = false;
            }
            else
            {
                control.IsEnabled = true;
            }
        }

        private static void SetReadOnly(FrameworkElement control)
        {
            object o = control.GetValue(RequiredEditRoleProperty);

            if (o == null)
            {
                return;
            }

            TextBox textBox = control as TextBox;
            if (textBox != null)
            {
                if (ThreadPrincipal == null)
                {
                    textBox.IsReadOnly = true;
                    return;
                }

                if (!ThreadPrincipal.IsInRole(o.ToString()))
                {
                    textBox.IsReadOnly = true;
                }
                else
                {
                    textBox.IsReadOnly = false;
                }

                return;
            }

            ComboBox comboBox = control as ComboBox;
            if (comboBox != null)
            {
                if (ThreadPrincipal == null)
                {
                    comboBox.IsReadOnly = true;
                    return;
                }

                if (!ThreadPrincipal.IsInRole(o.ToString()))
                {
                    comboBox.IsReadOnly = true;
                }
                else
                {
                    comboBox.IsReadOnly = false;
                }

                return;
            }

            Microsoft.Windows.Controls.DataGrid datagrid = control as Microsoft.Windows.Controls.DataGrid;
            if (datagrid != null)
            {
                if (ThreadPrincipal == null)
                {
                    datagrid.IsReadOnly = true;
                    return;
                }

                if (!ThreadPrincipal.IsInRole(o.ToString()))
                {
                    datagrid.IsReadOnly = true;
                }
                else
                {
                    datagrid.IsReadOnly = false;
                }

                return;
            }

            throw new Exception("RequiredEditRole can noly be used at TextBoxes, ComboBoxes and DatagGrid.");
        }
    }
}